package com.maoning.auth.web;

import com.alibaba.fastjson.TypeReference;
import com.maoning.auth.feign.MemberFeignService;
import com.maoning.auth.feign.ThirdPartyFeignService;
import com.maoning.auth.vo.UserLoginVo;
import com.maoning.auth.vo.UserRegistVo;
import com.maoning.common.constant.AuthServerConstant;
import com.maoning.common.exception.BizCodeEnume;
import com.maoning.common.utils.R;
import com.maoning.common.vo.MemberRespVo;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;

import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * @ClassName : LoginController
 * @Author : Administrator
 * @Date: 2022/4/1 17:16
 */
@Slf4j
@Controller
public class LoginController {
    @Autowired
    private ThirdPartyFeignService thirdPartyFeignService;
    @Autowired
    private StringRedisTemplate redisTemplate;
    @Autowired
    private MemberFeignService memberFeignService;


    @ResponseBody
    @GetMapping("/sms/sendCode")
    public R sendSms(@RequestParam("phone") String phone){
        // TODO: 2022/4/1 接口防刷还需要额外去解决,下面只是解决了手机验证码的防刷
        String codeUUID = UUID.randomUUID().toString().substring(0, 5);
        //新的阿里云短信测试模板只支持4-6位数字,所以写死一下
        codeUUID = "930105";
        //验证码防刷
        final String prefix = AuthServerConstant.SMS_CODE_CACHE_PREFIX;
        final String oldCode = redisTemplate.opsForValue().get(prefix + phone);

        if(StringUtils.isNotEmpty(oldCode)){
            final long l = Long.parseLong(StringUtils.split(oldCode, "_")[1]);
            if(System.currentTimeMillis() - l < 60000){
                return R.error(BizCodeEnume.SMS_CODE_EXCEPTION.getCode(),BizCodeEnume.SMS_CODE_EXCEPTION.getMsg());
            }
        }
        final R r = thirdPartyFeignService.sendSms(phone, codeUUID);
        redisTemplate.opsForValue().set(prefix + phone,codeUUID + "_" + System.currentTimeMillis(),10, TimeUnit.MINUTES);
        log.info("收到的验证码是:" + r.get("msg").toString());
        return R.ok();
    }

    //Request method 'POST' not supported
    //这里有一个点,因为之前使用的是mvc的视图页解析,
    // 所以这里使用"forward:/reg.html"的时候 post请求在跳转的时候就会保持post的状态发出页面跳转请求,但其实是不支持的.

    //RedirectAttributes是用来模拟重定向携带数据的 原理是利用了session,所以分布式下会有问题
    @PostMapping("/regist")
    public String regist(@Valid UserRegistVo userRegistVo, BindingResult bindingResult, Model model, RedirectAttributes redirectAttributes){
        if(bindingResult.hasErrors()){
            Map<String, String> errors = new HashMap<>();
            errors = bindingResult.getFieldErrors().stream().collect(Collectors.toMap(fieldError -> {
                        return fieldError.getField();
                    },
                    fieldError -> {
                        return fieldError.getDefaultMessage();
                    }));
//            model.addAttribute("errors", errors);
            redirectAttributes.addFlashAttribute("errors", errors);
//            校验出错则转发注册页
//            2种写法都可以,但是注意forward的时候就要自己带上前后缀了,而直接返回则不需要,可以由mvc来拼串
//            return "reg";
            log.info(errors.toString());
            return "redirect:http://auth.gulimall.com/reg.html";
        }

        //真正的注册,调用远程服务
        final String fullCode = redisTemplate.opsForValue().get(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegistVo.getPhone());
        if(StringUtils.isNotEmpty(fullCode)){
            final String userCode = userRegistVo.getCode();
            if(StringUtils.split(fullCode, "_")[0].equals(userCode)){
                //远程注册服务
                //删除验证码,令牌机制
                redisTemplate.delete(AuthServerConstant.SMS_CODE_CACHE_PREFIX + userRegistVo.getPhone());
                final R r = memberFeignService.regist(userRegistVo);
                if(r.getCode() == 0){
                    //注册成功
                    return "redirect:http://auth.gulimall.com/login.html";
                }else {
                    final String msg = (String) r.get("msg");
                    Map<String, String> errors = new HashMap<>();
                    errors.put("msg", msg);
                    redirectAttributes.addFlashAttribute("errors", errors);
                    return "redirect:http://auth.gulimall.com/reg.html";
                }

            }else {
                Map<String, String> errors = new HashMap<>();
                errors.put("code", "验证码输入不一致");
                redirectAttributes.addFlashAttribute("errors", errors);
                return "redirect:http://auth.gulimall.com/reg.html";
            }
        }else {
            Map<String, String> errors = new HashMap<>();
            errors.put("code", "验证码过期,请重新获取");
            redirectAttributes.addFlashAttribute("errors", errors);
            return "redirect:http://auth.gulimall.com/reg.html";
        }
        //注册成功返回登录页
//        return "login";
    }

    @PostMapping(value = "/login")
    public String login(UserLoginVo userLoginVo,RedirectAttributes redirectAttributes, HttpSession session){
        //调用远程登陆
        final R r = memberFeignService.login(userLoginVo);
        if(r.getCode() == 0){
            final MemberRespVo data = r.getData(new TypeReference<MemberRespVo>() {
            });
            session.setAttribute(AuthServerConstant.LOGIN_USER, data);
            return "redirect:http://gulimall.com";
        }else {
            Map<String,String> errors = new HashMap<>();
            errors.put("msg", (String) r.get("msg"));
            redirectAttributes.addFlashAttribute("errors",errors);
            return "redirect:http://auth.gulimall.com/login.html";
        }

    }
}
